/* Copyright 2010 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package activiti

import com.fasterxml.jackson.databind.JsonNode
import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.databind.node.ObjectNode
import org.activiti.bpmn.converter.BpmnXMLConverter
import org.activiti.bpmn.model.BpmnModel
import org.activiti.bpmn.model.FlowElement
import org.activiti.editor.constants.ModelDataJsonConstants
import org.activiti.editor.language.json.converter.BpmnJsonConverter
import org.activiti.engine.*
import org.activiti.engine.impl.cfg.ProcessEngineConfigurationImpl
import org.activiti.engine.repository.Deployment
import org.activiti.engine.repository.Model
import org.apache.batik.transcoder.TranscoderInput
import org.apache.batik.transcoder.TranscoderOutput
import org.apache.batik.transcoder.image.PNGTranscoder

import javax.xml.stream.XMLInputFactory
import javax.xml.stream.XMLStreamReader

/**
 *
 * @author <a href='mailto:limcheekin@vobject.com'>Lim Chee Kin</a>
 *
 * @since 5.0.beta2
 */
class ActivitService {
    ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine()

    RepositoryService repositoryService = processEngine.getRepositoryService()

    ObjectMapper objectMapper = new ObjectMapper()
    def utilsService


    def delModel(params) {
        def result = [success: true]
        if (!utilsService.validString(params.id)) {
            result.success = false
            result.errors = "参数 id  异常"
        } else {
            ActModel actModel = ActModel.get(params.id)
            if (actModel.status != '新建') {
                result.success = false
                result.errors = "模型状态不符合删除的要求"
            } else {
                actModel.delete()
                Model modelData = repositoryService.getModel(params.id)
                if (modelData)
                    repositoryService.deleteModel(modelData.id)
            }
        }
        return result
    }

    def deploy(params) {
        def result = true
        def record = params.request.JSON ?: params
        //获取模型
        Model modelData = repositoryService.getModel(record.id)
        byte[] bytes = repositoryService.getModelEditorSource(modelData.getId())
        if (bytes == null) {
            result = "模型数据为空，请先设计流程并成功保存，再进行发布"
            return result
        }
        JsonNode modelNode = new ObjectMapper().readTree(bytes)
        BpmnModel model = new BpmnJsonConverter().convertToBpmnModel(modelNode)
        if (model.getProcesses().size() == 0) {
            result = "数据模型不符要求，请至少设计一条主线流程"
            return result
        }
        byte[] bpmnBytes = new BpmnXMLConverter().convertToXML(model)
        //发布流程
        String processName = modelData.getName() + ".bpmn20.xml"
        Deployment deployment = repositoryService.createDeployment()
                .name(modelData.getName())
                .addString(processName, new String(bpmnBytes, "UTF-8"))
                .deploy()
        modelData.setDeploymentId(deployment.getId())
        repositoryService.saveModel(modelData)
        ActModel actModel = ActModel.get(modelData.id)
        if (actModel) {
            actModel.deploymentId = modelData.getDeploymentId()
            actModel.status = "发布"
            if (!actModel.save(flush: true)) {
                actModel.errors.each {
                    log.error(it)
                }

            }
        }
        return result
    }

    def newModel(params) {
        def record = params.request.JSON ?: params
        def modelId = []
        RepositoryService repositoryService = processEngine.getRepositoryService()
        //初始化一个空模型
        Model model = repositoryService.newModel()
        //设置一些默认信息
        int revision = 1
        String key = record.key
        ObjectNode modelNode = objectMapper.createObjectNode()
        modelNode.put(ModelDataJsonConstants.MODEL_NAME, record.name)
        modelNode.put(ModelDataJsonConstants.MODEL_DESCRIPTION, record.description)
        modelNode.put(ModelDataJsonConstants.MODEL_REVISION, revision)
        model.setName(record.name)
        model.setKey(key)
        model.setMetaInfo(modelNode.toString())
        repositoryService.saveModel(model)
        String id = model.getId()
        //  add ActModel
        ActModel actModel = ActModel.get(model.id)
        if (!actModel) {
            actModel = new ActModel(id: model.id)
        }
        actModel.properties = model.properties
        actModel.id = model.id
        actModel.description = record.description
        actModel.ctraterUserName = utilsService.currentUser?.username
        actModel.ctraterRealName = utilsService.currentUser?.realname
        actModel.typeCode = record.typeCode
        actModel.typeName = record.typeName
        actModel.bbms = record.bbms
        if (!actModel.save()) {
            actModel.errors.each {
                log.error(it.toString())
            }
        }
        //完善ModelEditorSource
        ObjectNode editorNode = objectMapper.createObjectNode()
        editorNode.put("id", "canvas")
        editorNode.put("resourceId", "canvas")
        ObjectNode stencilSetNode = objectMapper.createObjectNode()
        stencilSetNode.put("namespace", "http://b3mn.org/stencilset/bpmn2.0#")
        editorNode.put("stencilset", stencilSetNode)
        ObjectNode propertiesNode = objectMapper.createObjectNode()
        propertiesNode.put("process_id", key);
        propertiesNode.put("name", model.name);
        propertiesNode.put("documentation", "");
        editorNode.put("properties", propertiesNode)

        repositoryService.addModelEditorSource(id, editorNode.toString().getBytes("utf-8"))

//        modelId.add(id)
        def result = [success: true, modelId: id]
        result
    }
//  编辑时的保存
    def saveModel(params) {
        def record = params
        try {
            Model model = repositoryService.getModel(record.id)
            ObjectNode modelJson = (ObjectNode) objectMapper.readTree(model.getMetaInfo())
            modelJson.put("name", record.name);
            modelJson.put("description", record.description)
            model.setMetaInfo(modelJson.toString())
            model.setName(record.name)
            repositoryService.saveModel(model)
            //  add ActModel
            ActModel actModel = ActModel.get(model.id)
            if (!actModel) {
                actModel = new ActModel(id: model.id)
            }
            actModel.properties = model.properties
            actModel.id = model.id
            actModel.description = record.description
            actModel.ctraterUserName = utilsService.currentUser?.username
            actModel.ctraterRealName = utilsService.currentUser?.realname
            if (record.typeCode) actModel.typeCode = record.typeCode
            if (record.typeName) actModel.typeName = record.typeName
            if (record.bbms) actModel.bbms = record.bbms
            def map = utilsService.parseJSON2Map(record.json_xml)
//            log.debug("map-->"+map)
            actModel.key = map.properties.process_id
            actModel.name = map.properties.name
            if (!actModel.save()) {
                actModel.errors.each {
                    log.error(it.toString())
                }
            }
            repositoryService.addModelEditorSource(model.getId(), record.json_xml.getBytes("utf-8"))
            InputStream svgStream = new ByteArrayInputStream(record.svg_xml.getBytes("utf-8"))
            TranscoderInput input = new TranscoderInput(svgStream)
            PNGTranscoder transcoder = new PNGTranscoder()
            ByteArrayOutputStream outStream = new ByteArrayOutputStream()
            TranscoderOutput output = new TranscoderOutput(outStream)
            transcoder.transcode(input, output)
            final byte[] result = outStream.toByteArray()
            repositoryService.addModelEditorSourceExtra(model.getId(), result)
            outStream.close()

        } catch (Exception e) {
            throw new ActivitiException("Error saving model", e)
        }
        return true
    }

    def getTasksFromModel(params) {
        byte[] bytes = repositoryService.getModelEditorSource(params.id)
        JsonNode modelNode = new ObjectMapper().readTree(bytes)
        BpmnModel model = new BpmnJsonConverter().convertToBpmnModel(modelNode)
        def flowElements = model.getMainProcess().getFlowElements();
//        for(FlowElement e : flowElements) {
//            System.out.println("flowelement id:" + e.getId() + "  name:" + e.getName() + "   class:" + e.getClass().toString());
//        }
        def tList = flowElements.findAll { it.getClass().toString().contains("UserTask") }
        def result = [success: true, gridroot: []]
        tList.each { FlowElement flowElement ->
            result.gridroot << [taskId: flowElement.id, taskName: flowElement.name]
        }
        return result
    }

    def getBpmnModelfromXml(InputStream inputStream) {

        // InputStream inputStream = repositoryService.getResourceAsStream( processitionDefinition.getId(),sourceName);
        //创建转换对象
        BpmnXMLConverter converter = new BpmnXMLConverter();
        XMLInputFactory factory = XMLInputFactory.newInstance();
        XMLStreamReader reader = factory.createXMLStreamReader(inputStream);//createXmlStreamReader
        //将xml文件转换成BpmnModel
        BpmnModel bpmnModel = converter.convertToBpmnModel(reader);
//        repositoryService.addModelEditorSource(ModelID, modelNode.toString().getBytes("utf-8"));
        System.out.println();
        return bpmnModel
    }

    def impnewModel(inputStream) {
//        File file = new File("G:/u/AqhtfkProcess.bpmn20.xml");
//        InputStream inputStream = new FileInputStream(file);//实例化FileInputStream
        BpmnModel bpmnModel = getBpmnModelfromXml(inputStream);
        List<Process> pList = bpmnModel.processes
        pList.each { Process process ->
            Model model = repositoryService.newModel();
            ObjectNode modelJson = objectMapper.createObjectNode()
            modelJson.put("name", process.name);
            modelJson.put("description", "")
            model.setMetaInfo(modelJson.toString())
            model.setName(process.name)
            model.setKey(process.id)
            repositoryService.saveModel(model)
            //  add ActModel
            ActModel actModel = ActModel.get(model.id)
            if (!actModel) {
                actModel = new ActModel(id: model.id)
            }
            actModel.properties = model.properties
            actModel.id = model.id
            actModel.description =""
            actModel.ctraterUserName = utilsService.currentUser?.username
            actModel.ctraterRealName = utilsService.currentUser?.realname

            actModel.key = process.id
            actModel.name =process.name
            if (!actModel.save()) {
                actModel.errors.each {
                    log.error(it.toString())
                }
            }
//            repositoryService.addModelEditorSource(model.getId(), record.json_xml.getBytes("utf-8"))
            ObjectNode modelNode = new BpmnJsonConverter().convertToJson(bpmnModel);
            def svg_xml= new BpmnXMLConverter().convertToXML(bpmnModel,"utf-8")
            repositoryService.addModelEditorSource(model.getId(), modelNode.toString().getBytes("utf-8"));
//            InputStream svgStream = new ByteArrayInputStream(svg_xml)
//            TranscoderInput input = new TranscoderInput(svgStream)
//            PNGTranscoder transcoder = new PNGTranscoder()
//            ByteArrayOutputStream outStream = new ByteArrayOutputStream()
//            TranscoderOutput output = new TranscoderOutput(outStream)
//            transcoder.transcode(input, output)
//            final byte[] result = outStream.toByteArray()
//            repositoryService.addModelEditorSourceExtra(model.getId(), result)
//            outStream.close()
        }


    }

    def initTable(){
        ProcessEngineConfiguration.createProcessEngineConfigurationFromResourceDefault().setDatabaseSchemaUpdate(ProcessEngineConfigurationImpl.DB_SCHEMA_UPDATE_CREATE).buildProcessEngine();
    }
}
